package com.ynet.middleground.approve.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ynet.core.exception.BusinessException;
import com.ynet.middleground.approve.bean.GetImageReq;
import com.ynet.middleground.approve.dto.ProcessResourceDTO;

/**
 * @author liulx
 * @description 流程图资源业务处理类
 * @date 2019-10-20 23:27
 */
@Component
public class ProcessImageModel {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 根据流程定义ID获取流程图资源
     *
     * @param imageReq
     *            流程图资源请求对象
     * @return 流程图片文件流
     */
    public String getImageByDefinitionId(GetImageReq imageReq) throws IOException {
        if (StringUtils.isBlank(imageReq.getProcessDefinitionId())) {
            throw new BusinessException("流程定义ID不能为空", "ECAP0001");
        }
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionId(imageReq.getProcessDefinitionId()).singleResult();
        if (processDefinition == null) {
            throw new BusinessException("该流程定义信息不存在", "ECAP0100");
        }
        // 直接获取流程图文件
        /*InputStream is = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
            processDefinition.getDiagramResourceName());*/
        // 使用宋体
        String fontName = "宋体";
        // 获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(imageReq.getProcessDefinitionId());
        InputStream imageStream =
            processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator().generateDiagram(model, "png",
                Collections.EMPTY_LIST, new ArrayList<String>(), fontName, fontName, fontName, null, 1.0);
        return Base64.getEncoder().encodeToString(IOUtils.toByteArray(imageStream));
    }

    /**
     * 根据流程实例ID获取实时流程图资源
     *
     * @param imageReq
     *            流程图资源请求对象
     * @return 流程图片文件流
     */
    public String getImageByInstanceId(GetImageReq imageReq) throws IOException {
        String processInstanceId = imageReq.getProcessInstanceId();
        if (StringUtils.isBlank(imageReq.getProcessInstanceId())) {
            throw new BusinessException("流程实例ID不能为空", "ECAP0001");
        }
        // 获得流程实例
        ProcessInstance processInstance =
            runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            // 查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory =
                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null) {
                throw new BusinessException("流程实例信息不存在", "ECAP0200");
            }
            processDefinitionId = processInstanceHistory.getProcessDefinitionId();
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        // 使用宋体
        String fontName = "宋体";
        // 获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        // 获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;
        if (processInstance != null) {
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
        }

        InputStream imageStream =
            processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator().generateDiagram(model, "png",
                currentActs, new ArrayList<String>(), fontName, fontName, fontName, null, 1.0);
        return Base64.getEncoder().encodeToString(IOUtils.toByteArray(imageStream));
    }

    /**
     * 根据流程定义 Key 获取流程图资源
     *
     * @param imageReq
     *            流程图资源请求对象
     * @return 流程图片文件流
     * @throws IOException
     */
    public String getImageByProcessDefinitionKey(GetImageReq imageReq) throws IOException {
        String processDefinitionKey = imageReq.getProcessDefinitionKey();
        if (StringUtils.isBlank(processDefinitionKey)) {
            throw new BusinessException("流程定义 key 不能为空", "ECAP0001");
        }

        // 使用 latestVersion 来保证，只获取最新版本
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey(processDefinitionKey).latestVersion().singleResult();
        // 使用宋体
        String fontName = "宋体";
        // 获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        // 获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;

        InputStream imageStream =
            processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator().generateDiagram(model, "png",
                currentActs, new ArrayList<String>(), fontName, fontName, fontName, null, 1.0);
        return Base64.getEncoder().encodeToString(IOUtils.toByteArray(imageStream));
    }

    /**
     * 获取流程完整资源
     * 
     * @param imageReq
     *            获取流程图信息
     * @return 流程资源信息传输对象
     * @throws IOException
     */
    public ProcessResourceDTO getResource(GetImageReq imageReq) throws IOException {
        String processDefinitionId = imageReq.getProcessDefinitionId();
        String processInstanceId = imageReq.getProcessInstanceId();
        String processDefinitionKey = imageReq.getProcessDefinitionKey();
        ProcessDefinition processDefinition;
        List<String> currentActs = Collections.EMPTY_LIST;
        if (StringUtils.isNotBlank(processDefinitionKey)) {
            // 使用 latestVersion 来保证，只获取最新版本
            processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey).latestVersion().singleResult();
        } else if (StringUtils.isNotBlank(processDefinitionId)) {
            processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId).singleResult();
        } else if (StringUtils.isNotBlank(processInstanceId)) {
            // 根据流程实例 id 查询
            // 获得流程实例
            ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if (null == processInstance) {
                // 查询已经结束的流程实例
                HistoricProcessInstance processInstanceHistory = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
                if (processInstanceHistory == null) {
                    throw new BusinessException("流程实例信息不存在", "ECAP0200");
                }
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
            } else {
                processDefinitionId = processInstance.getProcessDefinitionId();
                // 如果该流程实例未结束，可以获取流程实例当前的节点
                currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
            }
            processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId).singleResult();

        } else {
            throw new BusinessException("流程定义 ID、流程实例 ID、流程定义 key 不可均为空", "ECAP0001");
        }

        if (processDefinition == null) {
            throw new BusinessException("该流程定义信息不存在", "ECAP0100");
        }

        String resourceName = processDefinition.getResourceName();
        InputStream resourceAsStream =
            repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        String encodeXML = Base64.getEncoder().encodeToString(IOUtils.toByteArray(resourceAsStream));

        ProcessResourceDTO dto = new ProcessResourceDTO();
        dto.setXml(encodeXML);
        dto.setActiveActivityIds(currentActs);
        return dto;
    }

}
